import { _decorator, CCFloat, CCInteger, Component, Enum, Label, log, Node, Size, Sprite, UITransform, Vec3 } from 'cc';
import { FlexItem } from './FlexItem';

const { ccclass, property } = _decorator;

// 定义行的接口
interface FlexLine {
    children: Node[];
    mainSize: number;    // 主轴总尺寸
    crossSize: number;   // 交叉轴尺寸（最大子项尺寸或拉伸后尺寸）
}

/**
 *  row（默认值）：主轴为水平方向，起点在左端。
    row-reverse：主轴为水平方向，起点在右端。
    column：主轴为垂直方向，起点在上沿。
    column-reverse：主轴为垂直方向，起点在下沿。
 */
enum FlexDirectionEnum {
    None = 0,
    Row,
    Row_Reverse,
    Column,
    Column_Reverse,
}

enum FlexWrapEnum {
    None = 0,
    Nowrap,
    Wrap,
    WrapReverse
}

/**
 *  flex-start（默认值）：左对齐
    flex-end：右对齐
    center： 居中
    space-between：两端对齐，项目之间的间隔都相等。
    space-around：每个项目两侧的间隔相等。所以，项目之间的间隔比项目与边框的间隔大一倍。
 */
enum JustifyContentEnum {
    None = 0,
    FlexStart,
    FlexEnd,
    Center,
    SpaceBetween,
    SpaceAround
}

/**
 *  flex-start：与交叉轴的起点对齐。
    flex-end：与交叉轴的终点对齐。
    center：与交叉轴的中点对齐。
    space-between：与交叉轴两端对齐，轴线之间的间隔平均分布。
    space-around：每根轴线两侧的间隔都相等。所以，轴线之间的间隔比轴线与边框的间隔大一倍。
    stretch（默认值）：轴线占满整个交叉轴
 */
enum AlignContentEnum {
    None = 0,
    FlexStart,
    FlexEnd,
    Center,
    SpaceBetween,
    SpaceAround,
    Stretch
}

/**
 *  flex-start：交叉轴的起点对齐。
    flex-end：交叉轴的终点对齐。
    center：交叉轴的中点对齐。
    baseline: 项目的第一行文字的基线对齐。
    stretch（默认值）：如果项目未设置高度或设为auto，将占满整个容器的高度。
 */
enum AlignItemEnum {
    None = 0,
    FlexStart,
    FlexEnd,
    Center,
    Baseline,
    Stretch
}

@ccclass('Flex')
export class Flex extends Component {

    @property({
        group: {
            name: 'container', id: '1', displayOrder: 1, style: 'section',
        }, tooltip: `[TODO] 属性决定主轴的方向（即项目的排列方向）。
        row（默认值）：主轴为水平方向，起点在左端。
        row- reverse：主轴为水平方向，起点在右端。
        column：主轴为垂直方向，起点在上沿。
        column - reverse：主轴为垂直方向，起点在下沿。`,
        type: Enum(FlexDirectionEnum),
    })
    set flex_direction(value: FlexDirectionEnum) {
        this._flex_direction = value;
        this.updateLayout();
    }

    get flex_direction() {
        return this._flex_direction
    }

    private _flex_direction: FlexDirectionEnum = FlexDirectionEnum.None;

    @property({
        group: {
            name: 'container', id: '1',
        }, tooltip: `[TODO] 默认情况下，项目都排在一条线（又称"轴线"）上。flex-wrap属性定义，如果一条轴线排不下，如何换行。
        nowrap（默认）：不换行。
        wrap：换行，第一行在上方。
        wrap-reverse：换行，第一行在下方。`, type: Enum(FlexWrapEnum)
    })
    set flex_wrap(value: FlexWrapEnum) {
        this._flex_wrap = value;
        this.updateLayout();
    }

    get flex_wrap() {
        return this._flex_wrap
    }

    private _flex_wrap: FlexWrapEnum = FlexWrapEnum.None;


    @property({
        group: {
            name: 'container', id: '1',
        }, tooltip: `[TODO]属性定义了项目在主轴上的对齐方式。
         flex-start（默认值）：左对齐
         flex-end：右对齐
         center： 居中
         space-between：两端对齐，项目之间的间隔都相等。
         space-around：每个项目两侧的间隔相等。所以，项目之间的间隔比项目与边框的间隔大一倍。`, type: Enum(JustifyContentEnum)
    })
    set justify_content(value: JustifyContentEnum) {
        this._justify_content = value;
        this.updateLayout();
    }

    get justify_content() {
        return this._justify_content
    }


    private _justify_content: JustifyContentEnum = JustifyContentEnum.None;

    @property({
        group: {
            name: 'container', id: '1',
        }, tooltip: `[TODO] 属性定义了多根轴线的对齐方式。如果项目只有一根轴线，该属性不起作用。
            flex-start：与交叉轴的起点对齐。
            flex-end：与交叉轴的终点对齐。
            center：与交叉轴的中点对齐。
            space-between：与交叉轴两端对齐，轴线之间的间隔平均分布。
            space-around：每根轴线两侧的间隔都相等。所以，轴线之间的间隔比轴线与边框的间隔大一倍。
            stretch（默认值）：轴线占满整个交叉轴。`
        , type: Enum(AlignContentEnum)
    })
    set align_content(value: AlignContentEnum) {
        this._align_content = value;
        this.updateLayout();
    }

    get align_content() {
        return this._align_content
    }

    private _align_content: AlignContentEnum = AlignContentEnum.None;



    @property({
        group: {
            name: 'container', id: '1',
        }, tooltip: `[TODO] 属性定义了多根轴线的对齐方式。如果项目只有一根轴线，该属性不起作用。
            flex-start：交叉轴的起点对齐。
            flex-end：交叉轴的终点对齐。
            center：交叉轴的中点对齐。
            baseline: 项目的第一行文字的基线对齐。
            stretch（默认值）：如果项目未设置高度或设为auto，将占满整个容器的高度。`
        , type: Enum(AlignItemEnum)
    })
    set align_items(value: AlignItemEnum) {
        this._align_items = value;
        this.updateLayout();
    }

    get align_items() {
        return this._align_items
    }

    private _align_items: AlignItemEnum = AlignItemEnum.None;

    @property({
        group: {
            name: 'container', id: '1',
        }, tooltip: `上内边距`
        , type: CCFloat
    })
    set padding_top(value: number) {
        this._padding_top = value;
        this.updateLayout();
    }

    get padding_top() {
        return this._padding_top
    }

    private _padding_top = 0

    @property({
        group: {
            name: 'container', id: '1',
        }, tooltip: `下内边距`
        , type: CCFloat
    })
    set padding_bottom(value: number) {
        this._padding_bottom = value;
        this.updateLayout();
    }

    get padding_bottom() {
        return this._padding_bottom
    }

    private _padding_bottom = 0

    @property({
        group: {
            name: 'container', id: '1',
        }, tooltip: `左内边距`
        , type: CCFloat
    })
    set padding_left(value: number) {
        this._padding_left = value;
        this.updateLayout();
    }

    get padding_left() {
        return this._padding_left
    }

    private _padding_left = 0

    @property({
        group: {
            name: 'container', id: '1',
        }, tooltip: `右内边距`
        , type: CCFloat
    })
    set padding_right(value: number) {
        this._padding_right = value;
        this.updateLayout();
    }

    get padding_right() {
        return this._padding_right
    }

    private _padding_right = 0


    private _contentSize: Size = new Size(0, 0); // 容器内容区域尺寸

    protected override onLoad(): void {
        this.updateLayout();
    }

    // 当子节点变化时自动更新布局
    protected override onEnable(): void {
        this.node.on(Node.EventType.CHILD_ADDED, this.updateLayout, this);
        this.node.on(Node.EventType.CHILD_REMOVED, this.updateLayout, this);
        this.node.on(Node.EventType.CHILDREN_ORDER_CHANGED, () => {
            console.log('CHILDREN_ORDER_CHANGED')
        }, this);
    }

    protected override onDisable(): void {
        this.node.off(Node.EventType.CHILD_ADDED, this.updateLayout, this);
        this.node.off(Node.EventType.CHILD_REMOVED, this.updateLayout, this);
    }

    // 核心布局方法
    public updateLayout(): void {
        log('updateLayout')
        const children = this.getValidChildren();
        if (children.length === 0) return;

        // 1. 计算容器可用空间（减去内边距）
        const containerSize = this.node.getComponent(UITransform)?.contentSize || new Size(0, 0);
        this._contentSize = new Size(
            containerSize.width - this.padding_left - this.padding_right,
            containerSize.height - this.padding_top - this.padding_bottom
        );

        // 2. 根据 flex-direction 确定主轴方向
        const isRow = this.flex_direction === FlexDirectionEnum.Row || this.flex_direction === FlexDirectionEnum.Row_Reverse;
        const mainAxis = isRow ? 'horizontal' : 'vertical';
        const isReverse = this.flex_direction === FlexDirectionEnum.Row_Reverse || this.flex_direction === FlexDirectionEnum.Column_Reverse;

        // 3. 对子项按 order 排序
        children.sort((a, b) => {
            const itemA = a.getComponent(FlexItem) || { order: 0 };
            const itemB = b.getComponent(FlexItem) || { order: 0 };
            return itemA.order - itemB.order;
        });

        // 4. 计算子项尺寸和布局
        this.layoutMainAxis(children, mainAxis, isReverse);
    }

    // 处理主轴布局
    private layoutMainAxis(children: Node[], mainAxis: 'horizontal' | 'vertical', isReverse: boolean): void {
        // 计算主轴总长度和弹性空间
        let totalMainSize = 0;
        const childSizes = children.map(child => {
            const transform = child.getComponent(UITransform)!;
            const size = mainAxis === 'horizontal' ? transform.width : transform.height;
            totalMainSize += size;
            return size;
        });

        // 判断是否需要换行
        const shouldWrap = this.flex_wrap !== FlexWrapEnum.Nowrap && totalMainSize > this._contentSize[mainAxis === 'horizontal' ? 'width' : 'height'];

        if (shouldWrap) {
            this.handleWrapping(children, mainAxis, isReverse);
        } else {
            this.handleSingleLine(children, mainAxis, isReverse);
        }
    }

    // 处理换行布局
    private handleWrapping(children: Node[], mainAxis: 'horizontal' | 'vertical', isReverse: boolean): void {
        // 1. 收集所有行
        const lines = this.collectFlexLines(children, mainAxis);

        // 2. 计算交叉轴总尺寸和剩余空间
        const containerCrossSize = this._contentSize[mainAxis === 'horizontal' ? 'height' : 'width'];
        const totalCrossSize = lines.reduce((sum, line) => sum + line.crossSize, 0);
        const crossRemaining = containerCrossSize - totalCrossSize;

        // 3. 处理 align-content: stretch（拉伸行高）
        if (this.align_content === AlignContentEnum.Stretch && lines.length > 0) {
            const stretchedCrossSize = (containerCrossSize - crossRemaining) / lines.length;
            lines.forEach(line => line.crossSize = stretchedCrossSize);
        }

        // 4. 计算行间对齐参数
        const { crossSpacing, crossOffset } = this.calculateAlignContent(lines.length, crossRemaining);

        // 5. 布局每一行
        let crossPos = crossOffset;
        lines.forEach(line => {
            this.layoutSingleLine(line.children, mainAxis, isReverse, crossPos);
            crossPos += line.crossSize + crossSpacing;
        });
    }

    // 收集所有行（根据主轴尺寸换行）
    private collectFlexLines(children: Node[], mainAxis: 'horizontal' | 'vertical'): FlexLine[] {
        const lines: FlexLine[] = [];
        let currentLine: FlexLine = { children: [], mainSize: 0, crossSize: 0 };
        const maxMainSize = this._contentSize[mainAxis === 'horizontal' ? 'width' : 'height'];

        children.forEach(child => {
            const childMainSize = this.getChildMainSize(child, mainAxis);
            // 换行条件：当前行已满且已有子项
            if (currentLine.mainSize + childMainSize > maxMainSize && currentLine.children.length > 0) {
                lines.push(currentLine);
                currentLine = { children: [], mainSize: 0, crossSize: 0 };
            }
            currentLine.children.push(child);
            currentLine.mainSize += childMainSize;
            // 更新行交叉轴尺寸（取最大子项尺寸）
            const childCrossSize = this.getChildCrossSize(child, mainAxis);
            currentLine.crossSize = Math.max(currentLine.crossSize, childCrossSize);
        });

        // 添加最后一行
        if (currentLine.children.length > 0) {
            lines.push(currentLine);
        }

        return lines; // 不再处理 stretch
    }
    // 布局单行（复用 handleSingleLine 的逻辑）
    private layoutSingleLine(children: Node[], mainAxis: 'horizontal' | 'vertical', isReverse: boolean, crossPos: number): void {
        const totalChildSize = children.reduce((sum, child) => sum + this.getChildMainSize(child, mainAxis), 0);
        const mainSize = this._contentSize[mainAxis === 'horizontal' ? 'width' : 'height'];
        const { spacing, startOffset } = this.calculateJustifyContent(children, totalChildSize, mainSize);

        let pos = 0;
        children.forEach((child, index) => {
            const childMainSize = this.getChildMainSize(child, mainAxis);
            const childPos = startOffset + pos + (index > 0 ? spacing : 0);
            this.setChildPosition(child, mainAxis, isReverse, childPos, crossPos);
            pos += childMainSize + (index > 0 ? spacing : 0);
        });
    }


    // 获取子项交叉轴尺寸
    private getChildCrossSize(child: Node, mainAxis: 'horizontal' | 'vertical'): number {
        const transform = child.getComponent(UITransform)!;
        return mainAxis === 'horizontal' ? transform.height : transform.width;
    }

    // 计算交叉轴对齐（align-content）
    private calculateAlignContent(lineCount: number, crossRemaining: number): { crossSpacing: number; crossOffset: number } {
        let crossSpacing = 0;
        let crossOffset = 0;

        switch (this.align_content) {
            case AlignContentEnum.FlexStart:
                crossOffset = 0;
                break;
            case AlignContentEnum.FlexEnd:
                crossOffset = crossRemaining;
                break;
            case AlignContentEnum.Center:
                crossOffset = crossRemaining / 2;
                break;
            case AlignContentEnum.SpaceBetween:
                crossSpacing = lineCount > 1 ? crossRemaining / (lineCount - 1) : 0;
                break;
            case AlignContentEnum.SpaceAround:
                crossSpacing = crossRemaining / lineCount;
                crossOffset = crossSpacing / 2;
                break;
            case AlignContentEnum.Stretch:
                crossSpacing = 0;
                crossOffset = 0;
                break;
        }

        return { crossSpacing, crossOffset };
    }

    // 处理单行布局
    private handleSingleLine(
        children: Node[],
        mainAxis: 'horizontal' | 'vertical',
        isReverse: boolean
    ): void {
        const mainSize = this._contentSize[mainAxis === 'horizontal' ? 'width' : 'height'];
        const totalChildSize = children.reduce((sum, child) => sum + this.getChildMainSize(child, mainAxis), 0);

        // 1. 计算主轴对齐参数
        const { spacing, startOffset } = this.calculateJustifyContent(children, totalChildSize, mainSize);

        // 2. 计算交叉轴起始位置（align-items 决定）
        const crossAxis = mainAxis === 'horizontal' ? 'vertical' : 'horizontal';
        const crossSize = this._contentSize[crossAxis === 'horizontal' ? 'width' : 'height'];
        const crossPos = this.calculateAlignItemsPosition(crossSize);

        // 3. 遍历子项设置位置
        let pos = 0;
        children.forEach((child, index) => {
            const childMainSize = this.getChildMainSize(child, mainAxis);
            const childPos = startOffset + pos + (index > 0 ? spacing : 0);

            // 调用 setChildPosition，传递完整的参数
            this.setChildPosition(
                child,
                mainAxis,
                isReverse,
                childPos,
                crossPos // 传递交叉轴起始位置
            );

            pos += childMainSize + (index > 0 ? spacing : 0);
        });
    }

    // 辅助方法：计算交叉轴起始位置（基于 align-items）
    private calculateAlignItemsPosition(crossSize: number): number {
        switch (this.align_items) {
            case AlignItemEnum.FlexStart:
                return 0;
            case AlignItemEnum.FlexEnd:
                return crossSize; // 实际位置需在 setChildPosition 中结合子项尺寸调整
            case AlignItemEnum.Center:
                return crossSize / 2;
            case AlignItemEnum.Stretch:
                return 0; // 拉伸时位置从 0 开始，尺寸会占满
            default:
                return 0;
        }
    }

    // 计算对齐方式（justify-content）
    private calculateJustifyContent(
        children: Node[],
        totalChildSize: number,
        mainSize: number
    ): { spacing: number; startOffset: number } {
        const remainingSpace = mainSize - totalChildSize;
        let spacing = 0;
        let startOffset = 0;

        switch (this.justify_content) {
            case JustifyContentEnum.FlexStart:
                startOffset = 0;
                break;
            case JustifyContentEnum.FlexEnd:
                startOffset = remainingSpace;
                break;
            case JustifyContentEnum.Center:
                startOffset = remainingSpace / 2;
                break;
            case JustifyContentEnum.SpaceBetween:
                if (children.length <= 1) {
                    spacing = 0;
                } else {
                    spacing = remainingSpace / (children.length - 1);
                }
                break;
            case JustifyContentEnum.SpaceAround:
                if (children.length === 0) {
                    spacing = 0;
                    startOffset = 0;
                } else {
                    spacing = remainingSpace / children.length;
                    startOffset = spacing / 2;
                }
                break;
        }

        return { spacing, startOffset };
    }
    // 更新设置子项位置的方法，加入交叉轴坐标
    private setChildPosition(
        child: Node,
        mainAxis: 'horizontal' | 'vertical',
        isReverse: boolean,
        mainPos: number,
        crossPos: number
    ): void {
        const transform = child.getComponent(UITransform)!;
        const mainSize = mainAxis === 'horizontal' ? transform.width : transform.height;
        const crossSize = mainAxis === 'horizontal' ? transform.height : transform.width;

        // 处理主轴反向
        if (isReverse) {
            mainPos = this._contentSize[mainAxis === 'horizontal' ? 'width' : 'height'] - mainPos - mainSize;
        }

        // 处理交叉轴对齐（align-items）
        switch (this.align_items) {
            case AlignItemEnum.FlexStart:
                break; // crossPos 已经是起点
            case AlignItemEnum.FlexEnd:
                crossPos += this._contentSize[mainAxis === 'horizontal' ? 'height' : 'width'] - crossSize;
                break;
            case AlignItemEnum.Center:
                crossPos += (this._contentSize[mainAxis === 'horizontal' ? 'height' : 'width'] - crossSize) / 2;
                break;
            case AlignItemEnum.Stretch:
                // 拉伸子项交叉轴尺寸
                if (mainAxis === 'horizontal') {
                    transform.height = this._contentSize.height;
                } else {
                    transform.width = this._contentSize.width;
                }
                break;
        }

        // 设置最终坐标（考虑内边距）
        const finalPos = new Vec3(
            mainAxis === 'horizontal' ? mainPos + this.padding_left : crossPos + this.padding_left,
            mainAxis === 'vertical' ? mainPos + this.padding_bottom : crossPos + this.padding_bottom,
            0
        );

        child.setPosition(finalPos);
    }

    // 辅助方法：获取有效子节点
    private getValidChildren(): Node[] {
        return this.node.children.filter(child => child.active);
    }

    // 辅助方法：获取子项主轴尺寸
    private getChildMainSize(child: Node, mainAxis: string): number {
        const transform = child.getComponent(UITransform)!;
        return mainAxis === 'horizontal' ? transform.width : transform.height;
    }


}


